package com.zhijian.warehouse.manage.util.cmmand;


import com.zhijian.util.BeanUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

/**
 * @Version 1.0.1
 */
public class CommandUtils {
    public static final int DEFAULT_INTERVAL = 100;
    private final static Logger logger = LoggerFactory.getLogger(CommandUtils.class);
    public static long startTime;

    /**
     * 执行命令
     *
     * @param command       命令地址
     * @param timeoutMillis 超时时间,毫秒
     * @return
     */
    public static CommandResult exec(String command, long timeoutMillis) {
        startTime = System.nanoTime();
        Process process = null;
        CommandResult commandResult = null;
        try {
            if (BeanUtil.isEmpty(command)) {
                commandResult = new CommandResult();
                commandResult.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT);
                commandResult.setError("command is not empty");
            }
            String[] cmd;
            String osName = System.getProperty("os.name");
            if (osName.startsWith("Windows")) {
                cmd = new String[3];
                // windows 95 only
                if ("Windows 95".equals(osName)) {
                    cmd[0] = "command.com";
                } else {
                    cmd[0] = "cmd.exe";
                }
                cmd[1] = "/C";
                cmd[2] = command;
            } else if ("Linux".equals(osName)) {//linux
                cmd = new String[3];
                cmd[0] = "/bin/sh";
                cmd[1] = "-c";
                cmd[2] = command;
            } else {
                cmd = new String[1];
                cmd[0] = command;
            }
            process = Runtime.getRuntime().exec(cmd);
            commandResult = wait(process, timeoutMillis);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        } finally {
            if (process != null)
                process.destroy();
        }
        return commandResult;
    }

    public static CommandResult wait(Process process, long timeout) throws InterruptedException, IOException {
        BufferedReader errorStreamReader = null;
        BufferedReader inputStreamReader = null;
        try {
            errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            boolean isFinished = false;
            while (true) {//超时 || 结束
                if ((TimeUnit.MILLISECONDS.toNanos(timeout) - (System.nanoTime() - startTime)) < 0) {//如果超时 ，直接返回
                    CommandResult result = new CommandResult();
                    result.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT);
                    result.setError("Timeout");
                    return result;
                }
                if (isFinished) {
                    CommandResult result = new CommandResult();
                    result.setExitValue(process.waitFor());
                    //error
                    if (errorStreamReader.ready()) {
                        StringBuilder buffer = new StringBuilder();
                        String line;
                        while ((line = errorStreamReader.readLine()) != null) {
                            buffer.append(line);
                        }
                        result.setError(buffer.toString());
                    }
                    //success
                    if (inputStreamReader.ready()) {
                        StringBuilder buffer = new StringBuilder();
                        String line;
                        while ((line = inputStreamReader.readLine()) != null) {
                            buffer.append(line);
                        }
                        result.setOutput(buffer.toString());
                    }
                    return result;
                }
                try {
                    isFinished = true;
                    process.exitValue();
                } catch (IllegalThreadStateException ex) {
                    isFinished = false;
                    Thread.sleep(DEFAULT_INTERVAL);
                }
            }
        } finally {
            if (errorStreamReader != null) {
                try {
                    errorStreamReader.close();
                } catch (IOException ex) {
                }
            }
            if (inputStreamReader != null) {
                try {
                    inputStreamReader.close();
                } catch (IOException ex) {
                }
            }
        }
    }
}
